use rand::distributions::{Distribution, Standard, Uniform};
use rand::Rng;
use rand_distr::{Normal, NormalError};

// 生成随机数
#[test]
fn gen_rand() {
    let mut rng = rand::thread_rng();

    let n1: u8 = rng.gen();
    let n2: u16 = rng.gen();
    println!("Random u8: {n1}");
    println!("Random u16: {n2}");
    println!("Random u32: {}", rng.gen::<u32>());
    println!("Random i32: {}", rng.gen::<i32>());
    println!("Random float: {}", rng.gen::<f64>());
}

// 生成范围内随机数: 半开放 [0,10)
#[test]
fn gen_rand_range() {
    let mut rng = rand::thread_rng();
    println!("Integer: {}", rng.gen_range(0..10));
    println!("Float: {}", rng.gen_range(0.0..10.0));
}

// Uniform模块可以得到均匀分布的值
// TODO 为什么此处一定要导入 Distribution??
#[test]
fn gen_rand_uniform() {
    let mut rng = rand::thread_rng();
    let die = Uniform::from(0..10);
    loop {
        let throw = die.sample(&mut rng);
        println!("Roll the die: {}", throw);
        if throw == 6 {
            break;
        }
    }
}

// 生成给定分布随机数
// 默认情况下,随机数在rand中是均匀分布
// 其他分布需要引入rand_distr, 下面是一个正态分布的示例
#[test]
fn gen_rand_distr() -> Result<(), NormalError> {
    let mut rng = rand::thread_rng();
    let normal = Normal::new(0.0, 10.0)?;
    let v = normal.sample(&mut rng);
    println!("{} is from a N(2,9) distribution", v);
    Ok(())
}

// 生成自定义类型随机值
#[derive(Debug)]
struct Point {
    x: i32,
    y: i32,
}

impl Distribution<Point> for Standard {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Point {
        let (x, y) = rng.gen();
        Point { x, y }
    }
}

#[test]
fn gen_rand_struct() {
    let mut rng = rand::thread_rng();
    let rand_tuple = rng.gen::<(i32, bool, f64)>();
    let rand_point = rng.gen::<Point>();
    println!("Random tuple: {:?}", rand_tuple);
    println!("Random Point: {:?}", rand_point);
    println!("Random Point x: {}, y: {}", rand_point.x, rand_point.y);
}

// 从一组字母数字字符串创建随机密码
#[test]
fn gen_rand_user_chars() {
    const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
        abcdefghijklmnopqrstuvwxyz\
        0123456789";
    const PASSWORD_LEN: usize = 30;
    let mut rng = rand::thread_rng();
    let password: String = (0..PASSWORD_LEN)
        .map(|_| {
            let idx = rng.gen_range(0..CHARSET.len());
            CHARSET[idx] as char
        })
        .collect();
    println!("Password: {:?}", password);
}

fn main() {}
